#ifndef _SECUENCIAL_INDEXADO_H_
#define _SECUENCIAL_INDEXADO_H_

/********************************************************************
 * SecuencialIndexado.h
 * 
 * Descripcion :Esta clase representa un archivo de datos que almacena
 * los mismos en forma secuencial indexada, utilizando un indice.
*********************************************************************/

#include "arch_datos.h"
#include "arch_bloques_libres.h"
#include "header.h"
#include "indice_arbol.h"
#include "bloque_sec.h"

#define EXT_EELL ".esp"
#define TAM_EELL 16

class SecuencialIndexado : public ArchivoDatos {
	//Atributos del archivo secuencial
	private:
		
		ArchBloquesLibres* bloques_libres; //Referencia al archivo de espacios libres
		
		//Constructor de copia privado para que no se pueda copiar un archivo
		SecuencialIndexado(SecuencialIndexado &s);
		
		void manejar_underflow(Bloque* bloque);
		
		bool fusionar_bloques(Bloque* b_actual,Bloque* b_izq);
		
		void redistribuir(Bloque* actual, Bloque* hno);
		
		void dividir_bloque(Bloque* bloque_actual,Bloque* bloque_nuevo,TipoStruct * reg);
		
		/*
		 * Crea un nuevo bloque y lo devuelve.
		 */
		Bloque* crear_bloque();
		
		/*
		 * Dado un bloque, se fija si la primera clave es distinta a la pasada como param
		 * y si esto pasa se actualiza el indice primario.
		 */
		void actualizar_primero(TipoDato* clave, Bloque* bloque);
		
	public:
	
		SecuencialIndexado(std::string& nombre, unsigned int tam_bloque, unsigned int tam_bloque_indice);
	
		~SecuencialIndexado();
	
		//Metodos heredados de la interfaz de archivo
		
		void abrir() throw(ExcepAbriendoArch);
				
		void crear(std::string formato) throw(ExcepCreandoArch, ExcepSintaxisParser, ExcepBloqueTam); 
		
		void cerrar();
		
		void ingresar(TipoStruct * reg) throw(ExcepArchCerrado,ExcepRegExistente, ExcepBloqueTam);
		
		void quitar(std::vector<ParesDatos*> &elementos, std::vector<TipoStruct*> &resultado) throw(ExcepArchCerrado);
		
		void consultar(std::vector<ParesDatos*> &consultas, std::vector<TipoStruct*> &resultado)
									 throw(ExcepArchCerrado,ExcepLeerBloque);
 		
 		void actualizar(TipoStruct * reg) throw(ExcepArchCerrado,ExcepRegInexistente, ExcepBloqueTam);
 													
 		TiposArchivo get_tipo_archivo();		
 		
 		void eliminar ();		
 		
 		/*
 		 * Devuelve el tamanio libre del archivo en cantidad de bytes.
 		 */
 		unsigned int get_espacio_libre() throw(ExcepArchCerrado, ExcepLeerBloque);
 		
 		/*
		 * Devuelve el espacio libre en bytes del indice primario.
		 */ 
		virtual unsigned int get_esp_libre_indice()  throw(ExcepArchCerrado, ExcepLeerBloque);
		 
		/*
		 * Devuelve la cantidad de registros del indice primario.
		 */ 										
		virtual unsigned int get_cant_regs_indice() throw(ExcepArchCerrado);
		
		/*
 		 * Devuelve el tamanio ocupado total por el indice primario, en bytes.
 		 */ 
 		virtual long get_tam_arch_indice() throw(ExcepArchCerrado);
 		
 	//Metodos de uso interno del archivo secuencial	
 		
 	private:
		
		/*
		 * Dado un bloque, y la pos y tamanio de un reg, saca el reg del bloque y decrementa la cant
		 * de registros en el bloque.
		 */
		int sacar_reg_bloque(Bloque* bloque, TipoStruct* reg, unsigned int pos_reg, unsigned int tam_reg);
		
		/*
		 * Dados un bloque y un reg pasado por param, serializa el reg y lo pone en el bloque al final
		 * del mismo si este entra. De ser asi devuelve true.
		 * Si el reg no entra en el bloque devuelve false.
		 */
 		bool poner_reg_en_bloque(Bloque* bloque, TipoStruct* reg);

		/*
		 * Devuelve true si el reg pasado como param no esta en el archivo,
		 * false en caso contrario.
		 */		
		bool es_unico(TipoStruct * reg);
		
		/*
		 * Devuelve la primera posicion donde se encuentran los registros
		 * en el archivo, es decir, luego de los tags de control
		 */ 
		unsigned int get_primera_pos(){
			return sizeof(unsigned int);
		}
		
};

#endif
